/**
 * @file bsp_adc.c
 * @brief
 * @author  ()
 * @version 1.0
 * @date 2024-09-13
 *
 * @copyright Copyright (C) 2019 Queclink Wireless Solutions (ShenZhen) Co., Ltd. All Rights Reserved.
 *
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2024-09-13 <td>1.0     <td>     <td>内容
 * </table>
 */
#include "bsp_log.h"
#include "bsp_adc.h"
#include "hal_adapter.h"
#include "global.h"

static ADC_ChannelConfTypeDef sConfig = {0};
static ADC_HandleTypeDef hadc1 = {0};

/**
 * @brief ADC1 Initialization Function
 * @param None
 * @retval None
 */
void bsp_adc_init(void)
{
	/** Common config
	 */
	hadc1.Instance = ADC_VER;
	hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV10;
	hadc1.Init.Resolution = ADC_RESOLUTION_12B;
	hadc1.Init.GainCompensation = 0;
	hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE;
	hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
	hadc1.Init.LowPowerAutoWait = DISABLE;
	hadc1.Init.ContinuousConvMode = ENABLE;
	hadc1.Init.NbrOfConversion = 1;
	hadc1.Init.DiscontinuousConvMode = DISABLE;
	hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  	hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; 
	hadc1.Init.DMAContinuousRequests = DISABLE;
	hadc1.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;
	hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
	hadc1.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE;
	hadc1.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
    hadc1.Init.OversamplingMode = DISABLE;
	if (HAL_ADC_Init(&hadc1) != HAL_OK)
	{
		return;
	}
	/* USER CODE BEGIN ADC1_Init 2 */
	/** Configure Regular Channel
	 */
    sConfig.Channel = ADC_VER_CHANNEL;                       /* Sampled channel number */
    sConfig.Rank = ADC_REGULAR_RANK_1;               /* Rank of sampled channel number ADCx_CHANNEL */
    sConfig.SamplingTime = ADC_SAMPLETIME_68CYCLES; /* Sampling time (unit: ADC clock cycles) */
    sConfig.SingleDiff = ADC_SINGLE_ENDED;           /* Single-ended input channel */
    sConfig.OffsetNumber = ADC_OFFSET_NONE;          /* No offset subtraction */
    sConfig.Offset = 0;                              /* Parameter discarded because offset correction is disabled */

    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    {
        /* Channel Configuration Error */
        return;
    }

#ifdef STM32U575xx
    __HAL_RCC_GPIOB_CLK_ENABLE();
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    GPIO_InitStruct.Pin = GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
#endif
}

/**
 * @brief ADC MSP Initialization
 * This function configures the hardware resources used in this example
 * @param hadc: ADC handle pointer
 * @retval None
 */
void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
	RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
	if (hadc->Instance == ADC_VER)
	{
		/* USER CODE BEGIN ADC1_MspInit 0 */

		/* USER CODE END ADC1_MspInit 0 */

		/** Initializes the peripherals clock
		 */
		PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADCDAC;
		PeriphClkInit.AdcDacClockSelection = ADC_VER_CLKSOURCE;
		if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
		{
		    Error_Handler();
		}

		/* ADC1 clock enable */
		__HAL_RCC_ADC12_CLK_ENABLE();

		ADC_VER_GPIO_CLK_ENABLE();
        /**ADC1 GPIO Configuration
            PA3     ------> ADC_INP15
        */
        GPIO_InitStruct.Pin = ADC_VER_PIN;
        GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(ADC_VER_PORT, &GPIO_InitStruct);
	}
}

/**
 * @brief ADC MSP De-Initialization
 * This function freeze the hardware resources used in this example
 * @param hadc: ADC handle pointer
 * @retval None
 */
void HAL_ADC_MspDeInit(ADC_HandleTypeDef *hadc)
{
    if (hadc->Instance == ADC_VER)
    {
        /* Peripheral clock disable */
        ADC_VER_CLK_DISABLE();

        /**ADC1 GPIO Configuration
        PA3     ------> ADC_INP15
        */
        HAL_GPIO_DeInit(ADC_VER_PORT, ADC_VER_PIN);
    }
}

/**
 * @brief Wait for ${timeout} seconds get the adc value.
 *
 * @param timeout Timeout value in millisecond.
 * @return uint32_t
 */
uint32_t bsp_adc_getvalue(uint32_t timeout)
{
    uint32_t res = 0;

    /* polling for the ADC result until successful conversion or conversion timeout.*/
    if (HAL_OK == HAL_ADC_PollForConversion(&hadc1, timeout))
    {
        res = HAL_ADC_GetValue(&hadc1);
    }

    return res;
}

/** 使能ADC采集输出 */
void bsp_adc_enable(uint8_t status)
{
#ifdef STM32U575xx
    if (status) {
        //  /* Run the ADC calibration in single-ended mode */
        if (HAL_ADCEx_Calibration_Start(&hadc1, ADC_CALIB_OFFSET_LINEARITY , ADC_SINGLE_ENDED) != HAL_OK) {
            /* Calibration Error */
            return;
        }

        HAL_ADC_Start(&hadc1);
        
        // output high level to PB1, then the PB0 can detect the advalue for hardware version
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
        HAL_Delay(200);
    } else {
        if (HAL_ADC_Stop(&hadc1) != HAL_OK) {
            return;
        }
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);
    }
#endif
}

#include "lettershell/shell.h"
/**
 * @brief  shell 测试接口
 */
int32_t shell_adc_value(void)
{
    bsp_adc_enable(1);
    printf("the hardward version ad value is:%u\r\n", bsp_adc_getvalue(50));
    bsp_adc_enable(0);
    return 0;
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC) | SHELL_CMD_DISABLE_RETURN,
                 get_adc, shell_adc_value, call get_adc to get the adc value of hardware version pin);